#pragma once

#include <memory>
#include <map>
#include <functional>
#include "Alice/ECS/EntityMngr.h"
#include "Alice/ECS/SystemMngr.h"
#include "Alice/Events/EventMngr.h"
#include "Alice/Timer/Timer.h"
#include "Alice/Core/QuadTree.h"
#include "Alice/Window/WindowInfo.hpp"
#include "Alice/Core/Scene.hpp"

namespace Alice
{

/* 
    世界类
    管理所有实体和系统
    封装访问实体管理器和系统管理器的方法
    以确保数据更新时能够同步到所有管理器
*/ 
class World
{
public:
    World();

    /* 
        创建一个实体
    */ 
    Entity CreateEntity();

    /* 
        销毁一个实体
    */ 
    void DestroyEntity(Entity entity);

    /* 
        获取一个实体的签名
    */ 
    Signature GetEntitySignature(Entity entity);

    /* 
        获取到指定签名的实体集合
    */ 
    std::set<Entity> GetEntitys(Signature signature);

    /* 
        模板函数
        向一个实体添加组件
    */ 
    template<typename T>
    T& AtachComp(Entity entity, T comp);

    /* 
        模板函数
        从实体中移除组件
    */ 
    template<typename T>
    void DeAtachComp(Entity entity);

    /* 
        模板函数
        获取到实体的组件
    */ 
    template<typename T>
    T& GetComp(Entity entity);

    /* 
        模板函数
        查询一个实体是否拥有组件
    */ 
    template<typename T>
    bool HaveComp(Entity entity);

    /* 
        模板函数
        注册一个系统
        \param signature 系统关注的实体，注册时会自动获取到该实体的签名
    */ 
    template<typename T>
    void RegisterSys(Entity entity);

    /*
        获得指定类型的系统实例指针    
    */
    template<typename T>
    T* GetSys();

    /* 
        循环执行开始前调用一次
        可以通过此方法来初始化数据
        而避免系统使用有参构造函数
    */ 
    void Before();

    /* 
        更新世界内一帧的内容
    */ 
    void Update();

    /* 
        循环执行结束后调用一次
    */ 
    void After();

    /*
        初始化四叉树
    */
    void InitQuadTree(WindowInfo& window_info);

    /*
        将一个实体添加到指定场景
    */
    void AddToScene(std::string scene_name, Entity entity);

    /*
        创建一个场景
    */
    void CreateScene(std::string scene_name);

    /*
        开始一个场景
        旧场景不会被加载
    */
    void StartScene(std::string scene_name);

    /*
        获得一个场景
    */
    Scene& GetCurrentScene();
    
    inline EventMngr* GetEventMngr() { return m_event_mngr.get(); }
    inline Timer& GetTimer() { return m_timer; }

private:
    // 世界计时器
    Timer m_timer;
    // 碰撞管理四叉树
    QuadTree m_quad_tree;
    // 场景集合
    std::map<std::string, Scene> m_scenes;
    // 当前场景
    std::string m_current_scene;
    // 实体管理器
    std::unique_ptr<EntityMngr> m_entity_mngr;
    // 系统管理器
    std::unique_ptr<SystemMngr> m_system_mngr;
    // 时间管理器
    std::unique_ptr<EventMngr> m_event_mngr;
};

template<class T> 
T& World::AtachComp(Entity entity, T comp)
{
    m_entity_mngr->AtachComp<T>(entity, comp);
    // 获取当前实体的签名
    Signature signature = m_entity_mngr->GetSignature(entity);
    // 实体签名变更，更新系统订阅的实体集合
    m_system_mngr->UpdateEntitys(entity, signature);
    
    return m_entity_mngr->GetComp<T>(entity);
}

template<class T>
void World::DeAtachComp(Entity entity)
{
    m_entity_mngr->DeAtachComp<T>(entity);
    Signature signature = m_entity_mngr->GetSignature(entity);
    m_system_mngr->UpdateEntitys(entity, signature);
}

template<class T>
T& World::GetComp(Entity entity)
{
    return m_entity_mngr->GetComp<T>(entity);
}

template<class T>
bool World::HaveComp(Alice::Entity entity)
{
    return m_entity_mngr->HaveComp<T>(entity);
}

template<class T>
void World::RegisterSys(Entity entity)
{
    Signature signature = GetEntitySignature(entity);
    m_system_mngr->Register<T>(signature, this);
    // 注册系统之后更新系统关注的实体
    m_system_mngr->SetEntitys<T>(m_entity_mngr->GetEntitys(signature));
}

template<class T>
T* World::GetSys()
{
    return m_system_mngr->GetSys<T>();
}

} // namespace Alice
